#include "napi/native_api.h"
#include "hilog/log.h"
#include "multimedia/player_framework/native_avscreen_capture.h"
#include "multimedia/player_framework/native_avscreen_capture_base.h"
#include "multimedia/player_framework/native_avscreen_capture_errors.h"
#include "native_buffer/native_buffer.h"
#include <malloc.h>
#include <unistd.h>

#define APP_LOG_DOMAIN 0x1027
#define APP_LOG_TAG "Winslei"

#define Winslei_LOGI(...) ((void)OH_LOG_Print(LOG_APP, LOG_INFO, APP_LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
#define Winslei_LOGD(...) ((void)OH_LOG_Print(LOG_APP, LOG_DEBUG, APP_LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
#define Winslei_LOGW(...) ((void)OH_LOG_Print(LOG_APP, LOG_WARN, APP_LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))
#define Winslei_LOGE(...) ((void)OH_LOG_Print(LOG_APP, LOG_ERROR, APP_LOG_DOMAIN, APP_LOG_TAG, __VA_ARGS__))

void OnError(struct OH_AVScreenCapture *capture, int32_t errorCode) {
    (void)capture;
    (void)errorCode;
}

void OnAudioBufferAvailable(struct OH_AVScreenCapture *capture, bool isReady, OH_AudioCaptureSourceType type) {
    if (isReady) {
        OH_AudioBuffer *audiobuffer = (struct OH_AudioBuffer *)malloc(sizeof(OH_AudioBuffer));
        // 获取音频流
        OH_AVSCREEN_CAPTURE_ErrCode acquireAudioBufferErrCode = OH_AVScreenCapture_AcquireAudioBuffer(capture, &audiobuffer, type);
        Winslei_LOGI("acquireAudioBufferErrCode: %{public}d", acquireAudioBufferErrCode);
        Winslei_LOGI("getAudioBuffe, size: %{public}d, timestamp: %{public}d", audiobuffer->size, audiobuffer->timestamp);
        /* get buffer */
        (void)audiobuffer->buf;
        /* getbuffer size */
        (void)audiobuffer->size;
        /* get audiobuffer timestamp */
        (void)audiobuffer->timestamp;
        free(audiobuffer);
        audiobuffer = nullptr;
        // 释放音频流
        OH_AVSCREEN_CAPTURE_ErrCode releaseAudioBufferErrCode = OH_AVScreenCapture_ReleaseAudioBuffer(capture, type);
        Winslei_LOGI("releaseAudioBufferErrCode: %{public}d", releaseAudioBufferErrCode);
    }
}

void OnVideoBufferAvailable(struct OH_AVScreenCapture *capture, bool isReady) {
    if (isReady) {
        int32_t fence = 0;
        int64_t timestamp = 0;
        struct OH_Rect damage;
        // 获取视频流buffer
        OH_NativeBuffer *buffer = OH_AVScreenCapture_AcquireVideoBuffer(capture, &fence, &timestamp, &damage);
        void *virAddr = nullptr;
        int32_t getNativeBufferErrCode = OH_NativeBuffer_Map(buffer, &virAddr); // 获取buffer
        Winslei_LOGI("getNativeBufferErrCode: %{public}d", getNativeBufferErrCode);
        OH_NativeBuffer_Config config;
        OH_NativeBuffer_GetConfig(buffer, &config); // 获取config信息 宽，高，format
        Winslei_LOGI("getConfig, width: %{public}d, height: %{public}d, format: %{public}d, usage: %{public}d, stride: %{public}d", config.width, config.height, config.format, config.usage, config.stride);
        // 释放视频流buffer
        int32_t releaseNativeBufferErrCode = OH_NativeBuffer_Unmap(buffer); 
        Winslei_LOGI("releaseNativeBufferErrCode: %{public}d", releaseNativeBufferErrCode);
        // 释放视频流
        OH_AVSCREEN_CAPTURE_ErrCode releaseVideoBufferErrCode = OH_AVScreenCapture_ReleaseVideoBuffer(capture);
        Winslei_LOGI("releaseVideoBufferErrCode: %{public}d", releaseVideoBufferErrCode);
    }
}

static napi_value StartCapture(napi_env env, napi_callback_info info)
{
    Winslei_LOGI("StartCapture enter");

    // 实例化ScreenCapture
    struct OH_AVScreenCapture *capture = OH_AVScreenCapture_Create();
    // 设置回调
    struct OH_AVScreenCaptureCallback callback;
    callback.onError = OnError;
    callback.onAudioBufferAvailable = OnAudioBufferAvailable;
    callback.onVideoBufferAvailable = OnVideoBufferAvailable;
    int32_t ret = OH_AVScreenCapture_SetCallback(capture, callback);
    // 初始化录屏，传入配置信息OH_AVScreenRecorderConfig
    OH_AudioCaptureInfo miccapinfo = {.audioSampleRate = 16000, .audioChannels = 2, .audioSource = OH_MIC};
    OH_VideoCaptureInfo videocapinfo = {
        .videoFrameWidth = 720, .videoFrameHeight = 1280, .videoSource = OH_VIDEO_SOURCE_SURFACE_RGBA};
    OH_AudioInfo audioinfo = {
        .micCapInfo = miccapinfo,
    };
    OH_VideoInfo videoinfo = {.videoCapInfo = videocapinfo};
    OH_AVScreenCaptureConfig config = {
        .captureMode = OH_CAPTURE_HOME_SCREEN,
        .dataType = OH_ORIGINAL_STREAM,
        .audioInfo = audioinfo,
        .videoInfo = videoinfo
    };
    OH_AVSCREEN_CAPTURE_ErrCode initCaptureErrCode = OH_AVScreenCapture_Init(capture, config);
    Winslei_LOGI("initCaptureErrCode: %{public}d", initCaptureErrCode);
    // mic开关设置
    OH_AVSCREEN_CAPTURE_ErrCode setMicrophoneEnabledErrCode = OH_AVScreenCapture_SetMicrophoneEnabled(capture, true);
    Winslei_LOGI("setMicrophoneEnabledErrCode: %{public}d", setMicrophoneEnabledErrCode);
    // 开始录屏
    OH_AVSCREEN_CAPTURE_ErrCode startScreenCaptureErrCode = OH_AVScreenCapture_StartScreenCapture(capture);
    Winslei_LOGI("startScreenCaptureErrCode: %{public}d", startScreenCaptureErrCode);
    // 录制3s
    sleep(3); 
    // 结束录屏
    OH_AVSCREEN_CAPTURE_ErrCode stopScreenCaptureErrCode = OH_AVScreenCapture_StopScreenCapture(capture);
    Winslei_LOGI("stopScreenCaptureErrCode: %{public}d", stopScreenCaptureErrCode);
    // 释放ScreenCapture
    OH_AVSCREEN_CAPTURE_ErrCode releaseCaptureErrCode = OH_AVScreenCapture_Release(capture);
    Winslei_LOGI("releaseCaptureErrCode: %{public}d", releaseCaptureErrCode);
    
    return 0;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "startCapture", nullptr, StartCapture, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "winsleiscreencapture",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}
